package com.spsoft.vatoutinv.service.issueinvoice.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.StringUtil;
import com.spsoft.system.entity.NvatOutInvoiceDetails;
import com.spsoft.system.entity.NvatOutInvoiceItems;
import com.spsoft.system.entity.NvatOutInvomapSelf;
import com.spsoft.system.entity.NvatRevmapinvoitems;
import com.spsoft.system.mapper.NvatOutInvoiceDetailsMapper;
import com.spsoft.system.mapper.NvatOutInvoiceItemsMapper;
import com.spsoft.system.mapper.NvatOutInvomapselfMapper;
import com.spsoft.system.mapper.NvatRevmapinvoitemsMapper;
import com.spsoft.system.service.SequenceService;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.entity.vmscreditlimit.VmsCreditLimit;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsenterpriseinforisk.VmsEnterpriseInfoRisk;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.entity.vmsfullyfmmessage.VmsFullYfmDetails;
import com.spsoft.vatoutinv.entity.vmsfullyfmmessage.VmsFullYfmMessage;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsApprovalHzqrd;
import com.spsoft.vatoutinv.entity.vmshzqrdmanage.VmsLeqiHzqrd;
import com.spsoft.vatoutinv.enums.CheckParamEnum;
import com.spsoft.vatoutinv.enums.CommonEnum;
import com.spsoft.vatoutinv.enums.SxedUpdateEnum;
import com.spsoft.vatoutinv.jobHandler.VmsUploadInvoiceJob;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceInfoDto;
import com.spsoft.vatoutinv.model.vo.issueinvoice.ErrorVerifyVo;
import com.spsoft.vatoutinv.service.issueinvoice.CheckDataService;
import com.spsoft.vatoutinv.service.issueinvoice.IssueInvoiceService;
import com.spsoft.vatoutinv.service.nvatoutinvoice.NvatOutInvoiceService;
import com.spsoft.vatoutinv.service.vmscreditlimit.VmsCreditLimitService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsenterpriseinforisk.VmsEnterpriseInfoRiskService;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.service.vmsfullyfmmessage.VmsFullYfmDetailsService;
import com.spsoft.vatoutinv.service.vmsfullyfmmessage.VmsFullYfmMessageService;
import com.spsoft.vatoutinv.service.vmshzqrdmanage.VmsApprovalHzqrdService;
import com.spsoft.vatoutinv.service.vmshzqrdmanage.VmsLeqiHzqrdService;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import com.spsoft.vms.redis.service.BswjRedisService;
import com.spsoft.vms.redis.service.impl.UploadInvoiceVmsQueueServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 公共发票开具接口实现类
 *
 * @author : chenxudong
 * @date : 2024/1/18 15:40
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class IssueInvoiceServiceImpl implements IssueInvoiceService {

    public static final String LOG_MSG = "(发票开具实现层)";

    private final RedisService redisService;

    private final BswjRedisService bswjRedisService;

    private final SequenceService sequenceService;

    private final VmsEnterpriseInfoService vmsEnterpriseInfoService;

    private final VmsEnterpriseInfoRiskService vmsEnterpriseInfoRiskService;

    private final VmsCreditLimitService vmsCreditLimitService;

    private final VmsFullYfmMessageService vmsFullYfmMessageService;

    private final VmsFullYfmDetailsService vmsFullYfmDetailsService;

    private final NvatOutInvoiceService nvatOutInvoiceService;

    private final NvatOutInvoiceDetailsMapper nvatOutInvoiceDetailsMapper;

    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;

    private final NvatOutInvomapselfMapper nvatOutInvomapselfMapper;

    private final NvatRevmapinvoitemsMapper nvatRevmapinvoitemsMapper;

    private final CheckDataService checkDataService;

    private final VmsLeqiHzqrdService vmsLeqiHzqrdService;

    private final VmsApprovalHzqrdService vmsApprovalHzqrdService;

    private final VmsFullOutInvoiceDetailsService vmsFullOutInvoiceDetailsService;

    private final VmsFullOutInvoiceItemsService vmsFullOutInvoiceItemsService;

    private final VmsFullOutInvoiceItemsExpService vmsFullOutInvoiceItemsExpService;

    private final VmsFullOutInvoiceItemsAddService vmsFullOutInvoiceItemsAddService;

    private final VmsFullOutInvoiceTdywService vmsFullOutInvoiceTdywService;

    private final VmsFullOutInvoiceTdywItemService vmsFullOutInvoiceTdywItemService;

    private final VmsFullOutInvoiceCekcService vmsFullOutInvoiceCekcService;

    private final UploadInvoiceVmsQueueServiceImpl uploadInvoiceVmsQueue;

    /**
     * 直连单位id
     */
    @Value("${leqi.zldwId}")
    private String zldwId;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> issueInvoice(List<VmsFullOutInvoiceInfoDto> invoiceDtoList, TokenUser tokenUser) {
        // tokenUser数据校验
        if (tokenUser == null) {
            return Result.ERROR(ResponseEnum.TOKENUSER_EMPTY_ERROR);
        }
        if (StringUtils.isBlank(tokenUser.getDeptCode())) {
            return Result.ERROR(ResponseEnum.DEPTCODE_EMPTY_ERROR);
        }
        if (StringUtils.isBlank(tokenUser.getUserCode())) {
            return Result.ERROR(ResponseEnum.USERCODE_EMPTY_ERROR);
        }
        if (StringUtils.isBlank(tokenUser.getUserName())) {
            return Result.ERROR(ResponseEnum.USERNAME_EMPTY_ERROR);
        }
        String redisLockKey = String.format(RedisConstant.REDIS_SYED_YFM_LOCK_KEY, tokenUser.getDeptCode());
        RLock lock = redisService.getLock(redisLockKey);
        boolean success = redisService.tryLock(lock, 3, 500);
        if (!success) {
            log.info("尝试指定次数后均未获取到锁，返回系统繁忙");
            return Result.ERROR(ResponseEnum.REDIS_LOCK_NO_GET);
        }
        log.info("{}redisson上锁成功，key：{}", LOG_MSG, redisLockKey);
        try {
            /*
             * 前置：判断当前机构是否暂停数电发票开具
             * 1.数据必填项、合法性校验
             * 2.判断纳税人开票资格
             * 3.价税分离并进行业务逻辑校验
             * 4.判断授信额度、预赋码是否充足
             * 5.发票赋码，授信额度更新，数据入库
             * 下面步骤后续可以放到获取发票上传结果成功之后进行更新
             * 6.红票更新蓝票发票状态：部分红冲还是全额红冲，红蓝票关联关系表入库
             * 7.流水开票发票流水关联关系表入库
             */
            log.info("{}接收到开票数据：{}", LOG_MSG, JSONObject.toJSONString(invoiceDtoList));

            // 校验当前机构 数电发票开具开关 是否启用
            boolean fpkjzt = bswjRedisService.getFpkjztSwitch(tokenUser.getDeptCode());
            if (!fpkjzt) {
                log.error("{}发票开具状态校验不通过：{}", LOG_MSG, ResponseEnum.BUSINESS_SWITCH_NOT_ENABLE_FPKJ.getMsg());
                return Result.ERROR(ResponseEnum.BUSINESS_SWITCH_NOT_ENABLE_FPKJ);
            }

            // 1.数据必填项、合法性校验
            List<ErrorVerifyVo> errorVerifyList = checkRequestParam(invoiceDtoList);
            if (CollectionUtil.isNotEmpty(errorVerifyList)) {
                log.error("{}数据必填项、合法性校验不通过：{}", LOG_MSG, JSONObject.toJSONString(errorVerifyList));
                return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyList);
            }

            // 2.判断纳税人开票资质
            Result<Object> result = checkInfoAndRisk(tokenUser.getDeptCode());
            if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
                log.error("{}纳税人开票资格校验不通过：{}", LOG_MSG, result.getMessage());
                return result;
            }

            // 3.价税分离并进行业务逻辑校验
            List<ErrorVerifyVo> errorVerifyList2 = checkDataService.checkDataBusiness(invoiceDtoList,
                    tokenUser.getDeptCode(), CommonEnum.CHECK_SOURCE_2.getKey());
            if (CollectionUtil.isNotEmpty(errorVerifyList2)) {
                log.error("{}业务逻辑校验校验不通过：{}", LOG_MSG, JSONObject.toJSONString(errorVerifyList2));
                return Result.ERROR(ResponseEnum.ISSUE_INVOICE_VERIFY_ERROR, errorVerifyList2);
            }

            // 开票数据补全（备注、（个人）标注）
            fillRequestParam(invoiceDtoList);

            // 不含税金额合计
            BigDecimal bhsjeTotal = BigDecimal.ZERO;
            // 计算蓝字发票不含税金额合计
            for (VmsFullOutInvoiceInfoDto invoiceInfoDto : invoiceDtoList) {
                if (CommonEnum.INVOICE_BLUE.getKey().equals(invoiceInfoDto.getVmsFullOutInvoiceDetails().getLzfpbz())) {
                    bhsjeTotal = bhsjeTotal.add(invoiceInfoDto.getVmsFullOutInvoiceDetails().getHjje());
                }
            }

            boolean sxedSuccess = false, yfmSuccess = false;
            // 判断授信额度-已下载未使用额度 是否大于等于 本次开票使用的授信额度
            VmsCreditLimit sxed = vmsCreditLimitService.getSxedByDeptCode(tokenUser.getDeptCode());
            if (sxed != null && sxed.getYxzwsyed().compareTo(bhsjeTotal) >= 0) {
                sxedSuccess = true;
            }

            // 判断预赋码号段剩余总数 是否大于等于 发票申请数量
            List<VmsFullYfmMessage> yfmMessageList = vmsFullYfmMessageService.getYfmByDeptCode(tokenUser.getDeptCode());
            if (CollectionUtil.isNotEmpty(yfmMessageList)) {
                long hdsyzs = yfmMessageList.stream().mapToLong(VmsFullYfmMessage::getHdsyzs).sum();
                if (hdsyzs >= invoiceDtoList.size()) {
                    yfmSuccess = true;
                }
            }

            // 校验授信额度和预赋码是否满足开票条件
            if (!sxedSuccess && !yfmSuccess) {
                log.error("{}已下载未使用额度不足！预赋码号段不足！", LOG_MSG);
                return Result.ERROR(ResponseEnum.CREDIT_AND_YFM_DEFICIENCY_ERROR);
            }
            if (!sxedSuccess) {
                log.error("{}已下载未使用额度不足！", LOG_MSG);
                return Result.ERROR(ResponseEnum.CREDIT_LIMIT_DEFICIENCY_ERROR);
            }
            if (!yfmSuccess) {
                log.error("{}预赋码号段不足！", LOG_MSG);
                return Result.ERROR(ResponseEnum.YFM_DEFICIENCY_ERROR);
            }

            // 授信额度更新
            if (bhsjeTotal.compareTo(BigDecimal.ZERO) > 0) {
                Boolean update = vmsCreditLimitService.updateSxed(CommonConstant.SXED_REDUCE, SxedUpdateEnum.SXED_BLUE,
                                                                    bhsjeTotal, sxed, tokenUser);
                if (!update) {
                    throw new BusinessException(ResponseEnum.SQL_ROLLBACK_ERROR);
                }
            }

            // 预付码分配
            List<VmsFullYfmDetails> yfmDetailsList = vmsFullYfmMessageService.yfmDistribution(yfmMessageList, (long) invoiceDtoList.size(), tokenUser);

            // 官网需要发票号码
            List<String> fphmList = new ArrayList<>();
            // 将开票数据保存到数电发票信息表
            for (int i = 0; i < invoiceDtoList.size(); i++) {
                VmsFullOutInvoiceInfoDto vmsFullOutInvoiceInfoDto = invoiceDtoList.get(i);
                VmsFullOutInvoiceDetails invoiceDetail = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceDetails();
                List<VmsFullOutInvoiceItems> invoiceItemsList = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceItemsList();
                VmsFullOutInvoiceItemsExp invoiceItemsExp = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceItemsExp();
                List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceItemsAddList();
                List<VmsFullOutInvoiceTdyw> invoiceTdywList = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceTdywList();
                List<VmsFullOutInvoiceCekc> invoiceCekcList = vmsFullOutInvoiceInfoDto.getVmsFullOutInvoiceCekcList();

                VmsFullYfmDetails vmsFullYfmDetails = yfmDetailsList.get(i);
                // 官网需要发票号码
                fphmList.add(vmsFullYfmDetails.getFphm());
                // 数据补全
                Date date = new Date();
                invoiceDetail.setFoidid(null);
                invoiceDetail.setKprq(date);
                invoiceDetail.setCreatTime(date);
                invoiceDetail.setUpdateTime(date);
                invoiceDetail.setFphm(vmsFullYfmDetails.getFphm());
                invoiceDetail.setSczt(CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey());
                invoiceDetail.setFpzt(CommonEnum.INVOICE_STATUS_0.getKey());
                invoiceDetail.setKpzt(CommonEnum.KPZT_2.getKey());
                invoiceDetail.setDelFlag(CommonEnum.DEL_STATUS_0.getKey());
                if (StringUtil.equalsAny(invoiceDetail.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey())) {
                    invoiceDetail.setSfbdc(CommonEnum.SFBDC_YES.getKey());
                } else {
                    invoiceDetail.setSfbdc(CommonEnum.SFBDC_NO.getKey());
                }
                invoiceDetail.setPtbh(zldwId);
                // 插入老系统发票主信息表并获取主键id
                Long oidId = nvatOutInvoiceService.insertNvatOutInvoiceDetails(invoiceDetail, tokenUser.getDeptCode(), null);
                invoiceDetail.setOidid(oidId);
                log.info("{}保存数电发票主信息", LOG_MSG);
                vmsFullOutInvoiceDetailsService.save(invoiceDetail);

                // 更新预赋码明细信息
                LambdaUpdateWrapper<VmsFullYfmDetails> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(VmsFullYfmDetails::getFplx, invoiceDetail.getFppz());
                updateWrapper.set(VmsFullYfmDetails::getFoidid, StringUtil.toString(invoiceDetail.getFoidid()));
                updateWrapper.set(VmsFullYfmDetails::getKplx, invoiceDetail.getSjly());
                updateWrapper.set(VmsFullYfmDetails::getUpdateUser, invoiceDetail.getCreatBy());
                updateWrapper.set(VmsFullYfmDetails::getUpdateTime, date);
                updateWrapper.eq(VmsFullYfmDetails::getDetailId, vmsFullYfmDetails.getDetailId());
                vmsFullYfmDetailsService.update(updateWrapper);

                // 数电发票明细信息
                Long foidId = invoiceDetail.getFoidid();
                // 遍历明细信息
                for (VmsFullOutInvoiceItems invoiceItem : invoiceItemsList) {
                    // 设置发票ID
                    invoiceItem.setFiviid(null);
                    invoiceItem.setFoidid(foidId);
                    invoiceItem.setOidid(oidId);
                    invoiceItem.setCreatTime(date);
                    // 计算含税单价，老系统使用
                    if (StringUtils.isNotBlank(invoiceItem.getSl())) {
                        BigDecimal jshj = invoiceItem.getJe().add(invoiceItem.getSe());
                        BigDecimal hsdj = jshj.divide(new BigDecimal(invoiceItem.getSl()), 6, RoundingMode.HALF_UP);
                        invoiceItem.setHsdj(hsdj.stripTrailingZeros().toPlainString());
                    }
                    if (CommonEnum.CEZS_01.getKey().equals(invoiceDetail.getCezslxdm())) {
                        // 全额开票将扣除额置为0
                        invoiceItem.setKce(BigDecimal.ZERO);
                    } else if (StringUtils.isBlank(invoiceDetail.getCezslxdm())) {
                        // 非差额开票扣除额置为空
                        invoiceItem.setKce(null);
                    }
                    // 插入老系统发票明细信息表并获取主键id
                    Long iviId = nvatOutInvoiceService.insertNvatOutInvoiceItems(invoiceItem, oidId);
                    invoiceItem.setIviid(iviId);
                }
                log.info("{}保存数电发票明细信息", LOG_MSG);
                // 按照明细序号的顺序入库
                invoiceItemsList = invoiceItemsList.stream().sorted(Comparator.comparing(VmsFullOutInvoiceItems::getMxxh)).collect(Collectors.toList());
                vmsFullOutInvoiceItemsService.saveBatch(invoiceItemsList);

                // 保存发票扩展信息
                if (ObjectUtil.isNotEmpty(invoiceItemsExp)) {
                    invoiceItemsExp.setZkId(null);
                    invoiceItemsExp.setFoidid(foidId);
                    log.info("{}保存数电发票非必填扩展信息", LOG_MSG);
                    vmsFullOutInvoiceItemsExpService.save(invoiceItemsExp);
                }

                // 保存发票附加要素信息
                if (CollectionUtil.isNotEmpty(invoiceItemsAddList)) {
                    for (VmsFullOutInvoiceItemsAdd invoiceItemsAdd : invoiceItemsAddList) {
                        invoiceItemsAdd.setFjid(null);
                        invoiceItemsAdd.setFoidid(foidId);
                    }
                    log.info("{}保存数电发票附加要素信息", LOG_MSG);
                    vmsFullOutInvoiceItemsAddService.saveBatch(invoiceItemsAddList);
                }

                // 保存特定业务信息
                if (CollectionUtil.isNotEmpty(invoiceTdywList)) {
                    // 不动产销售服务发票、不动产租赁服务发票 特定业务信息只有一条
                    // 旅客运输服务发票 特定业务信息可以有多条
                    if (CommonEnum.TDYS_05.getKey().equals(invoiceDetail.getTdys())
                            || CommonEnum.TDYS_06.getKey().equals(invoiceDetail.getTdys())
                            || CommonEnum.TDYS_09.getKey().equals(invoiceDetail.getTdys())) {
                        for (VmsFullOutInvoiceTdyw invoiceTdyw : invoiceTdywList) {
                            invoiceTdyw.setTdywId(null);
                            invoiceTdyw.setFoidid(foidId);
                            log.info("{}保存数电发票特定业务信息", LOG_MSG);
                            vmsFullOutInvoiceTdywService.save(invoiceTdyw);

                            // 不动产销售服务发票，共同购买方处理
                            if (CommonEnum.TDYS_05.getKey().equals(invoiceDetail.getTdys())
                                    && CommonConstant.STR_Y.equals(invoiceTdyw.getDfgtgmbz())) {
                                List<VmsFullOutInvoiceTdywItem> tdywItemList = invoiceTdyw.getTdywItemList();
                                for (VmsFullOutInvoiceTdywItem tdywItem : tdywItemList) {
                                    tdywItem.setId(null);
                                    tdywItem.setTdywId(invoiceTdyw.getTdywId());
                                }
                                log.info("{}保存数电发票特定业务附加信息", LOG_MSG);
                                vmsFullOutInvoiceTdywItemService.saveBatch(tdywItemList);
                            }
                        }
                    }
                }

                // 保存发票差额扣除信息
                if (CommonEnum.CEZS_02.getKey().equals(invoiceDetail.getCezslxdm())
                        && CollectionUtil.isNotEmpty(invoiceCekcList)) {
                    for (int j = 0; j < invoiceCekcList.size(); j++) {
                        VmsFullOutInvoiceCekc invoiceCekc = invoiceCekcList.get(j);
                        invoiceCekc.setId(null);
                        invoiceCekc.setFoidid(foidId);
                        invoiceCekc.setXh((long) j + 1);
                    }
                    log.info("{}保存数电发票差额扣除信息", LOG_MSG);
                    vmsFullOutInvoiceCekcService.saveBatch(invoiceCekcList);
                }

                // 流水开票、官网开票维护发票明细和流水关联关系
                if (CommonEnum.DATA_SOURCE_0.getKey().equals(invoiceDetail.getSjly())
                        || CommonEnum.DATA_SOURCE_2.getKey().equals(invoiceDetail.getSjly())) {
                    for (VmsFullOutInvoiceItems invoiceItem : invoiceItemsList) {
                        String[] rdids = invoiceItem.getRdid().split("、");
                        for (String rdid : rdids) {
                            NvatRevmapinvoitems nvatRevmapinvoitems = new NvatRevmapinvoitems();
                            nvatRevmapinvoitems.setNrmivid(sequenceService.getSequence(CommonConstant.NVAT_REVMAPINVOITEMS));
                            nvatRevmapinvoitems.setOidid(invoiceItem.getOidid());
                            nvatRevmapinvoitems.setIviid(invoiceItem.getIviid());
                            nvatRevmapinvoitems.setRdid(Long.valueOf(rdid));
                            nvatRevmapinvoitemsMapper.insert(nvatRevmapinvoitems);
                        }
                    }
                }

                // 红票处理
                if (CommonEnum.INVOICE_RED.getKey().equals(invoiceDetail.getLzfpbz())) {
                    // 将红字确认单已开具红字发票标志修改为 已开具
                    LambdaQueryWrapper<VmsLeqiHzqrd> hzqrdQuery = new LambdaQueryWrapper<>();
                    hzqrdQuery.eq(VmsLeqiHzqrd::getHzfpxxqrdbh, invoiceDetail.getHzqrxxdbh());
                    hzqrdQuery.eq(VmsLeqiHzqrd::getQydjid, tokenUser.getDeptCode());
                    VmsLeqiHzqrd leqiHzqrd = vmsLeqiHzqrdService.getOne(hzqrdQuery);
                    LambdaUpdateWrapper<VmsLeqiHzqrd> update1 = new LambdaUpdateWrapper<>();
                    update1.set(VmsLeqiHzqrd::getYkjhzfpbz, CommonEnum.YKJHZFP_YES.getKey());
                    update1.set(VmsLeqiHzqrd::getHzfphm, invoiceDetail.getFphm());
                    update1.set(VmsLeqiHzqrd::getHzkprq, invoiceDetail.getKprq());
                    update1.set(VmsLeqiHzqrd::getFoidid, invoiceDetail.getFoidid());
                    update1.set(VmsLeqiHzqrd::getUpdateTime, new Date());
                    update1.set(VmsLeqiHzqrd::getUpdateBy, invoiceDetail.getCreatBy());
                    update1.eq(VmsLeqiHzqrd::getId, leqiHzqrd.getId());
                    vmsLeqiHzqrdService.update(update1);

                    LambdaQueryWrapper<VmsApprovalHzqrd> hzqrdQuery2 = new LambdaQueryWrapper<>();
                    hzqrdQuery2.eq(VmsApprovalHzqrd::getHzfpxxqrdbh, invoiceDetail.getHzqrxxdbh());
                    hzqrdQuery2.eq(VmsApprovalHzqrd::getQydjid, tokenUser.getDeptCode());
                    VmsApprovalHzqrd approvalHzqrd = vmsApprovalHzqrdService.getOne(hzqrdQuery2);
                    LambdaUpdateWrapper<VmsApprovalHzqrd> update2 = new LambdaUpdateWrapper<>();
                    update2.set(VmsApprovalHzqrd::getYkjhzfpbz, CommonEnum.YKJHZFP_YES.getKey());
                    update2.set(VmsApprovalHzqrd::getHzfphm, invoiceDetail.getFphm());
                    update2.set(VmsApprovalHzqrd::getHzkprq, invoiceDetail.getKprq());
                    update2.set(VmsApprovalHzqrd::getUpdateTime, new Date());
                    update2.set(VmsApprovalHzqrd::getUpdateBy, invoiceDetail.getCreatBy());
                    update2.eq(VmsApprovalHzqrd::getId, approvalHzqrd.getId());
                    vmsApprovalHzqrdService.update(update2);

                    // 查找红票对应的蓝票
                    LambdaQueryWrapper<NvatOutInvoiceDetails> query = new LambdaQueryWrapper<>();
                    query.eq(NvatOutInvoiceDetails::getFphm, invoiceDetail.getDylzfphm());
                    NvatOutInvoiceDetails nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query);
                    if (nvatOutInvoiceDetails == null) {
                        // 如果没查到，判断红冲的是税控发票，对应蓝字发票号码的填写规则为税控发票的发票代码+发票号码
                        if (invoiceDetail.getDylzfphm() != null && invoiceDetail.getDylzfphm().length() == 20) {
                            LambdaQueryWrapper<NvatOutInvoiceDetails> query2 = new LambdaQueryWrapper<>();
                            query2.eq(NvatOutInvoiceDetails::getFpdm, invoiceDetail.getDylzfphm().substring(0, 12));
                            query2.eq(NvatOutInvoiceDetails::getFphm, invoiceDetail.getDylzfphm().substring(12));
                            nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query2);
                        } else if (invoiceDetail.getDylzfphm() != null && invoiceDetail.getDylzfphm().length() == 18) {
                            // 此处兼容老增值税发票，发票代码为10位
                            LambdaQueryWrapper<NvatOutInvoiceDetails> query2 = new LambdaQueryWrapper<>();
                            query2.eq(NvatOutInvoiceDetails::getFpdm, invoiceDetail.getDylzfphm().substring(0, 10));
                            query2.eq(NvatOutInvoiceDetails::getFphm, invoiceDetail.getDylzfphm().substring(10));
                            nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query2);
                        } else {
                            throw new BusinessException(ResponseEnum.DYLZFPHM_ERROR);
                        }
                    }

                    if (nvatOutInvoiceDetails != null) {
                        LambdaQueryWrapper<NvatOutInvoiceItems> query3 = new LambdaQueryWrapper<>();
                        query3.eq(NvatOutInvoiceItems::getOidid, nvatOutInvoiceDetails.getOidid());
                        query3.orderByAsc(NvatOutInvoiceItems::getIviid);
                        List<NvatOutInvoiceItems> nvatOutInvoiceItemList = nvatOutInvoiceItemsMapper.selectList(query3);

                        // 维护老系统红蓝票关联关系表
                        for (VmsFullOutInvoiceItems redInvoiceItem : invoiceItemsList) {
                            NvatOutInvoiceItems nvatOutInvoiceItems = nvatOutInvoiceItemList.get(Math.toIntExact(redInvoiceItem.getDylzfpmxxh() - 1));
                            NvatOutInvomapSelf nvatOutInvomapself = new NvatOutInvomapSelf();
                            nvatOutInvomapself.setNoimsid(sequenceService.getSequence(CommonConstant.NVAT_OUTINVOMAPSELF));
                            nvatOutInvomapself.setOoidid(nvatOutInvoiceItems.getOidid());
                            nvatOutInvomapself.setOiviid(nvatOutInvoiceItems.getIviid());
                            nvatOutInvomapself.setNoidid(redInvoiceItem.getOidid());
                            nvatOutInvomapself.setNiviid(redInvoiceItem.getIviid());
                            nvatOutInvomapselfMapper.insert(nvatOutInvomapself);
                        }

                        // 更新原蓝票的发票状态（税控表）
                        LambdaUpdateWrapper<NvatOutInvoiceDetails> update = new LambdaUpdateWrapper<>();
                        update.set(NvatOutInvoiceDetails::getFpzt, 3);
                        update.set(NvatOutInvoiceDetails::getZfchyy, invoiceDetail.getZfchyy());
                        update.set(NvatOutInvoiceDetails::getZfchrq, invoiceDetail.getZfchrq());
                        update.eq(NvatOutInvoiceDetails::getOidid, nvatOutInvoiceDetails.getOidid());
                        nvatOutInvoiceDetailsMapper.update(null, update);

                        // 更新原蓝票的发票状态（数电表）
                        LambdaQueryWrapper<VmsFullOutInvoiceDetails> query4 = new LambdaQueryWrapper<>();
                        query4.eq(VmsFullOutInvoiceDetails::getFphm, invoiceDetail.getDylzfphm());
                        VmsFullOutInvoiceDetails vmsInvoice = vmsFullOutInvoiceDetailsService.getOne(query4);
                        if (vmsInvoice != null) {
                            LambdaUpdateWrapper<VmsFullOutInvoiceDetails> invUpdate = new LambdaUpdateWrapper<>();
                            String fpzt = judgeOldInvoiceFpzt(nvatOutInvoiceDetails);
                            invUpdate.set(VmsFullOutInvoiceDetails::getFpzt, fpzt);
                            invUpdate.set(VmsFullOutInvoiceDetails::getZfchyy, invoiceDetail.getZfchyy());
                            invUpdate.set(VmsFullOutInvoiceDetails::getZfchrq, invoiceDetail.getZfchrq());
                            invUpdate.set(VmsFullOutInvoiceDetails::getUpdateBy, invoiceDetail.getCreatBy());
                            invUpdate.set(VmsFullOutInvoiceDetails::getUpdateTime, new Date());
                            invUpdate.eq(VmsFullOutInvoiceDetails::getFoidid, vmsInvoice.getFoidid());
                            vmsFullOutInvoiceDetailsService.update(invUpdate);
                        }

                        // 蓝票为当月开具，则增加本月授信额度
                        String blueTime = DateUtil.format(nvatOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_6);
                        String redTime = DateUtil.format(invoiceDetail.getKprq(), CommonConstant.DATE_FORMAT_6);
                        if (redTime.equals(blueTime)) {
                            // 授信额度更新
                            Boolean updateFlag = vmsCreditLimitService.updateSxed(CommonConstant.SXED_ADD, SxedUpdateEnum.SXED_RED,
                                                                                    invoiceDetail.getHjje().abs(), sxed, tokenUser);
                            if (!updateFlag) {
                                throw new BusinessException(ResponseEnum.SQL_ROLLBACK_ERROR);
                            }
                        }
                    }
                }
                // 将发票主键id放入数电票上传队列，后续定时任务进行数电票上传操作
                boolean flag = uploadInvoiceVmsQueue.addMessageToQueue(invoiceDetail.getFoidid());
                if (!flag) {
                    throw new BusinessException(ResponseEnum.REDIS_QUEUE_ERROR);
                }
            }
            return Result.OK(fphmList);
        } catch (BusinessException e) {
            log.error("{}出现业务异常:{}", LOG_MSG, e);
            throw new BusinessException(e.getCode(), e.getMsg());
        } catch (Exception e) {
            log.error("{}出现未知异常:{}", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.ERROR);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                log.info("{}redisson释放锁成功，key为:{}", LOG_MSG, redisLockKey);
                lock.unlock();
            } else {
                log.info("{}redisson释放锁失败，key为:{}", LOG_MSG, redisLockKey);
            }
        }
    }

    /**
     * 判断纳税人开票资质
     */
    private Result<Object> checkInfoAndRisk(String deptCode) {
        // 根据当前登录机构的纳税人识别号获取纳税人基本信息
        VmsEnterpriseInfo vmsEnterpriseInfo = vmsEnterpriseInfoService.getInfoByRedis(deptCode);
        log.info("{}获取到的纳税人基本信息：{}", LOG_MSG, JSONObject.toJSONString(vmsEnterpriseInfo));

        // 根据当前登录机构的纳税人识别号获取纳税人风险信息
        VmsEnterpriseInfoRisk vmsEnterpriseInfoRisk = vmsEnterpriseInfoRiskService.getRiskInfoByRedis(deptCode);
        log.info("{}获取到的纳税人风险信息：{}", LOG_MSG, JSONObject.toJSONString(vmsEnterpriseInfoRisk));

        // 校验纳税人基本信息和纳税人风险信息
        ResponseEnum responseEnum = checkEnterpriseInfoAndRisk(vmsEnterpriseInfo, vmsEnterpriseInfoRisk);
        if (!ResponseEnum.SUCCESS.getCode().equals(responseEnum.getCode())) {
            return Result.ERROR(responseEnum);
        }

        return Result.OK();
    }

    /**
     * 校验纳税人基本信息和纳税人风险信息是否满足开票条件
     */
    private ResponseEnum checkEnterpriseInfoAndRisk(VmsEnterpriseInfo vmsEnterpriseInfo, VmsEnterpriseInfoRisk vmsEnterpriseInfoRisk) {
        /*
        如果纳税人识别号对应的“开票方纳税人状态”非“正常”或“报验中”，则弹窗提示：“当前机构的“开票方纳税人状态”非“正常”或“报验中”，不允许手工开票，请核实纳税人基本信息！”；
        如果纳税人识别号对应的“风险纳税人类型”为“Ⅰ类（高风险）纳税人”，则弹窗提示：“当前机构的“风险纳税人类型”为“Ⅰ类（高风险）纳税人”，不允许手工开票，请核实纳税人风险信息！”；
        纳税人识别号对应的“纳税人预警级别”为“红色预警”，则弹窗提示：“当前机构的“纳税人预警级别”为“红色预警”，不允许手工开票，请核实纳税人风险信息！”；
        纳税人识别号对应的“风险纳税人标志”为“Y（风险纳税人）”则弹窗提示：“当前机构的“风险纳税人标志”为“Y（风险纳税人）”，不允许手工开票，请核实纳税人风险信息！”。
        */

        if (vmsEnterpriseInfo == null || vmsEnterpriseInfo.getId() == null) {
            return ResponseEnum.INTERFACE_ENT_INFO_ERROR1;
        }

        if (vmsEnterpriseInfoRisk == null || vmsEnterpriseInfoRisk.getId() == null) {
            return ResponseEnum.INTERFACE_ENT_RISK_ERROR1;
        }

        if (!StrUtil.equalsAny(vmsEnterpriseInfo.getNsrztdm(), CommonEnum.ENTERPRISE_INFO_STATUS_03.getKey(), CommonEnum.ENTERPRISE_INFO_STATUS_09.getKey())) {
            return ResponseEnum.INTERFACE_ENT_INFO_ERROR2;
        }

        if (CommonEnum.RISK_TYPE_01.getKey().equals(vmsEnterpriseInfoRisk.getFxnsrlx())) {
            return ResponseEnum.INTERFACE_ENT_RISK_ERROR2;
        }

        if (CommonEnum.RISK_WARNING_LEVEL_01.getKey().equals(vmsEnterpriseInfoRisk.getNsryjjb())) {
            return ResponseEnum.INTERFACE_ENT_RISK_ERROR3;
        }

        if (CommonEnum.RISK_FLAG_Y.getKey().equals(vmsEnterpriseInfoRisk.getFxnsrbz())) {
            return ResponseEnum.INTERFACE_ENT_RISK_ERROR4;
        }

        return ResponseEnum.SUCCESS;
    }

    /**
     * 判断原蓝字发票冲红状态
     * @param nvatOutInvoiceDetails 原蓝字发票信息
     * @return 7：部分红冲，8：全额红冲
     */
    private String judgeOldInvoiceFpzt(NvatOutInvoiceDetails nvatOutInvoiceDetails) {
        String fpzt = CommonEnum.INVOICE_STATUS_7.getKey();

        LambdaQueryWrapper<NvatOutInvomapSelf> selfQuery = new LambdaQueryWrapper<>();
        selfQuery.eq(NvatOutInvomapSelf::getOoidid, nvatOutInvoiceDetails.getOidid());
        List<NvatOutInvomapSelf> nvatSelfList = nvatOutInvomapselfMapper.selectList(selfQuery);
        // oracle中的group by不好使，使用stream流根据noidid(红票主表id)去重
        nvatSelfList = nvatSelfList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() ->
                new TreeSet<>(Comparator.comparing(p -> StringUtil.toString(p.getNoidid())))), ArrayList::new));

        // 老系统红蓝票关联关系表未查到数据，说明该蓝票没有被红冲过，直接返回
        if (CollectionUtil.isEmpty(nvatSelfList)) {
            fpzt = CommonEnum.INVOICE_STATUS_0.getKey();
        }

        // 冲红金额合计、红冲税额合计
        BigDecimal chjeTotal = BigDecimal.ZERO, chseTotal = BigDecimal.ZERO;
        for (NvatOutInvomapSelf nvatSelf : nvatSelfList) {
            LambdaQueryWrapper<NvatOutInvoiceDetails> invoiceQuery = new LambdaQueryWrapper<>();
            invoiceQuery.eq(NvatOutInvoiceDetails::getOidid, nvatSelf.getNoidid());
            NvatOutInvoiceDetails nvatInvoice = nvatOutInvoiceDetailsMapper.selectOne(invoiceQuery);
            if (nvatInvoice != null) {
                chjeTotal = chjeTotal.add(nvatInvoice.getHjje().abs());
                chseTotal = chseTotal.add(nvatInvoice.getHjse().abs());
            }
        }

        if (chjeTotal.compareTo(nvatOutInvoiceDetails.getHjje()) == 0
            && chseTotal.compareTo(nvatOutInvoiceDetails.getHjse()) == 0) {
            fpzt = CommonEnum.INVOICE_STATUS_8.getKey();
        }

        return fpzt;
    }

    /**
     * （备注、（个人）标注）
     */
    private void fillRequestParam(List<VmsFullOutInvoiceInfoDto> invoiceDtoList) {
        for (VmsFullOutInvoiceInfoDto invoiceInfoDto : invoiceDtoList) {
            VmsFullOutInvoiceDetails invoiceDetail = invoiceInfoDto.getVmsFullOutInvoiceDetails();
            VmsFullOutInvoiceItemsExp invoiceItemsExp = invoiceInfoDto.getVmsFullOutInvoiceItemsExp();
            List<VmsFullOutInvoiceItems> invoiceItemsList = invoiceInfoDto.getVmsFullOutInvoiceItemsList();

            // 需要补充的备注信息
            String formatBz = "";

            // 蓝票补充备注
            if (CommonEnum.INVOICE_BLUE.getKey().equals(invoiceDetail.getLzfpbz())) {
                // 差额征税备注
                if (CommonConstant.STR_02.equals(invoiceDetail.getCezslxdm())) {
                    String cezsBz = String.format(CommonConstant.CEZS_BZ, invoiceItemsList.get(0).getKce());
                    if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(cezsBz)) {
                        formatBz = formatBz + cezsBz + "\n";
                    }
                }

                // 特定业务发票备注
                if (StrUtil.equalsAny(invoiceDetail.getTdys(), CommonEnum.TDYS_05.getKey(), CommonEnum.TDYS_06.getKey())) {
                    // 之前的业务校验通过了，说明tdywList不为空
                    VmsFullOutInvoiceTdyw invoiceTdyw = invoiceInfoDto.getVmsFullOutInvoiceTdywList().get(0);
                    // 不动产销售服务发票
                    if (CommonEnum.TDYS_05.getKey().equals(invoiceDetail.getTdys())) {
                        // 不动产单元代码/网签合同备案编号两者只能填一个
                        String bdcdwdm = StringUtils.isBlank(invoiceTdyw.getBdcdwdm()) ? invoiceTdyw.getWqhtbabh() : invoiceTdyw.getBdcdwdm();
                        // 不动产地址
                        String bdcdz = StringUtil.toString(invoiceTdyw.getBdczldzS()) + StringUtil.toString(invoiceTdyw.getBdczldzS1())
                                + StringUtil.toString(invoiceTdyw.getBdczldzXxdz());

                        String bdcxsBz = String.format(CommonConstant.BDCXS_BZ,
                                StringUtils.isBlank(bdcdwdm) ? "-" : bdcdwdm,
                                StringUtils.isBlank(bdcdz) ? "-" : bdcdz,
                                CommonConstant.STR_Y.equals(invoiceTdyw.getKdsbz()) ? "是" : "否",
                                StringUtils.isBlank(invoiceTdyw.getTdzzsxmbh()) ? "-" : invoiceTdyw.getTdzzsxmbh(),
                                ObjectUtil.isEmpty(invoiceTdyw.getHdjsjg()) ? "-" : invoiceTdyw.getHdjsjg().toPlainString(),
                                ObjectUtil.isEmpty(invoiceTdyw.getSjcjhsje()) ? "-" : invoiceTdyw.getSjcjhsje().toPlainString());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(bdcxsBz)) {
                            formatBz = formatBz + bdcxsBz + "\n";
                        }
                    }
                    // 不动产租赁服务发票
                    if (CommonEnum.TDYS_06.getKey().equals(invoiceDetail.getTdys())) {
                        // 不动产地址
                        String bdcdz = StringUtil.toString(invoiceTdyw.getBdczldzS()) + StringUtil.toString(invoiceTdyw.getBdczldzS1())
                                + StringUtil.toString(invoiceTdyw.getBdczldzXxdz());

                        String bdczlBz = String.format(CommonConstant.BDCZL_BZ,
                                StringUtils.isBlank(bdcdz) ? "-" : bdcdz,
                                StringUtils.isBlank(invoiceTdyw.getZlqqz()) ? "-" : invoiceTdyw.getZlqqz(),
                                CommonConstant.STR_Y.equals(invoiceTdyw.getKdsbz()) ? "是" : "否");
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(bdczlBz)) {
                            formatBz = formatBz + bdczlBz + "\n";
                        }
                    }
                }

                if (invoiceItemsExp != null) {
                    // 是否展示购买方银行账号标签
                    if (CommonConstant.STR_Y.equals(invoiceItemsExp.getSfzsgmfyhzhbq())) {
                        String gmfyhzhbqBz = String.format(CommonConstant.GMFYHZHBQ_BZ,
                                StringUtils.isBlank(invoiceItemsExp.getGmfkhh()) ? "-" : invoiceItemsExp.getGmfkhh(),
                                StringUtils.isBlank(invoiceItemsExp.getGmfzh()) ? "-" : invoiceItemsExp.getGmfzh());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(gmfyhzhbqBz)) {
                            formatBz = formatBz + gmfyhzhbqBz + "\n";
                        }
                    }

                    // 是否展示销售方银行账号标签
                    if (CommonConstant.STR_Y.equals(invoiceItemsExp.getSfzsxsfyhzhbq())) {
                        String xsfyhzhbqBz = String.format(CommonConstant.XSFYHZHBQ_BZ,
                                StringUtils.isBlank(invoiceItemsExp.getXsfkhh()) ? "-" : invoiceItemsExp.getXsfkhh(),
                                StringUtils.isBlank(invoiceItemsExp.getXsfzh()) ? "-" : invoiceItemsExp.getXsfzh());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(xsfyhzhbqBz)) {
                            formatBz = formatBz + xsfyhzhbqBz + "\n";
                        }
                    }

                    // 收款人、复核人备注
                    // 1.有收款人无复核人
                    if (StringUtils.isNotBlank(invoiceItemsExp.getSkrxm()) && StringUtils.isBlank(invoiceItemsExp.getFhrxm())) {
                        String skrBz = String.format(CommonConstant.SKR_BZ, invoiceItemsExp.getSkrxm());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(skrBz)) {
                            formatBz = formatBz + skrBz + "\n";
                        }
                    }
                    // 2.无收款人有复核人
                    if (StringUtils.isBlank(invoiceItemsExp.getSkrxm()) && StringUtils.isNotBlank(invoiceItemsExp.getFhrxm())) {
                        String fhrBz = String.format(CommonConstant.FHR_BZ, invoiceItemsExp.getFhrxm());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(fhrBz)) {
                            formatBz = formatBz + fhrBz + "\n";
                        }
                    }
                    // 3.有收款人有复核人
                    if (StringUtils.isNotBlank(invoiceItemsExp.getSkrxm()) && StringUtils.isNotBlank(invoiceItemsExp.getFhrxm())) {
                        String skrfhrBz = String.format(CommonConstant.SKRFHR_BZ, invoiceItemsExp.getSkrxm(), invoiceItemsExp.getFhrxm());
                        if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(skrfhrBz)) {
                            formatBz = formatBz + skrfhrBz + "\n";
                        }
                    }
                }
            }

            // 红票补充备注
            if (CommonEnum.INVOICE_RED.getKey().equals(invoiceDetail.getLzfpbz())) {
                String redBz;
                if (CommonEnum.SJKLY_SK.getKey().equals(invoiceDetail.getSjkly())) {
                    String lzfpdm = "", lzfphm = "";
                    if (invoiceDetail.getDylzfphm().length() == 20) {
                        lzfpdm = invoiceDetail.getDylzfphm().substring(0, 12);
                        lzfphm = invoiceDetail.getDylzfphm().substring(12);
                    } else if (invoiceDetail.getDylzfphm().length() == 18) {
                        // 此处兼容老增值税发票，发票代码为10位
                        lzfpdm = invoiceDetail.getDylzfphm().substring(0, 10);
                        lzfphm = invoiceDetail.getDylzfphm().substring(10);
                    }
                    // 被红冲蓝字发票代码：%s 蓝字发票号码：%s 红字发票信息确认单编号：%s
                    redBz = String.format(CommonConstant.RED_BZ_SK, lzfpdm, lzfphm, invoiceDetail.getHzqrxxdbh());
                } else {
                    // 被红冲蓝字数电票号码：%s 红字发票信息确认单编号：%s
                    redBz = String.format(CommonConstant.RED_BZ_SD, invoiceDetail.getDylzfphm(), invoiceDetail.getHzqrxxdbh());
                }
                if (StringUtils.isBlank(invoiceDetail.getBz()) || !invoiceDetail.getBz().contains(redBz)) {
                    formatBz = formatBz + redBz + "\n";
                }
            }

            // 补充备注信息
            if (StringUtils.isNotBlank(formatBz)) {
                log.info("{}需要补充的备注信息：{}", LOG_MSG, formatBz);
                invoiceDetail.setBz(formatBz + (StringUtils.isBlank(invoiceDetail.getBz()) ? "" : invoiceDetail.getBz()));
                // 校验备注是否超长
                if (invoiceDetail.getBz().length() > 450) {
                    throw new BusinessException(ResponseEnum.INVOICE_BZ_LENGTH_ERROR);
                }
            }

            // 数电普票且购方自然人标识为是，购买方名称追加（个人）
            if (CommonEnum.INVOICE_TYPE_02.getKey().equals(invoiceDetail.getFppz())
                && invoiceItemsExp != null && CommonEnum.PERSON_FLAG_01.getKey().equals(invoiceItemsExp.getGmfzrrbz())) {
                // 判断购方名称是否包含（个人）
                if (StringUtils.isNotBlank(invoiceDetail.getGmfmc()) && !invoiceDetail.getGmfmc().endsWith(CommonConstant.PERSON)) {
                    invoiceDetail.setGmfmc(invoiceDetail.getGmfmc() + CommonConstant.PERSON);
                }
            }
        }
    }

    /**
     * 数据必填项、合法性校验
     */
    private List<ErrorVerifyVo> checkRequestParam(List<VmsFullOutInvoiceInfoDto> invoiceDtoList) {
        List<ErrorVerifyVo> errorVerifyList = new ArrayList<>();

        if (CollectionUtil.isEmpty(invoiceDtoList)) {
            ErrorVerifyVo errorVerify = buildErrorVerify("第1张发票", "发票主信息", "发票数据为空");
            errorVerifyList.add(errorVerify);
            return errorVerifyList;
        }

        for (int i = 0; i < invoiceDtoList.size(); i++) {
            VmsFullOutInvoiceInfoDto invoiceDto = invoiceDtoList.get(i);
            VmsFullOutInvoiceDetails invoiceDetails = invoiceDto.getVmsFullOutInvoiceDetails();
            List<VmsFullOutInvoiceItems> invoiceItemsList = invoiceDto.getVmsFullOutInvoiceItemsList();
            VmsFullOutInvoiceItemsExp invoiceItemsExp = invoiceDto.getVmsFullOutInvoiceItemsExp();
            List<VmsFullOutInvoiceItemsAdd> invoiceItemsAddList = invoiceDto.getVmsFullOutInvoiceItemsAddList();
            List<VmsFullOutInvoiceTdyw> invoiceTdywList = invoiceDto.getVmsFullOutInvoiceTdywList();

            String num = "第" + (i + 1) + "张发票";
            // 校验发票主信息
            if (ObjectUtil.isNotEmpty(invoiceDetails)) {
                // 参数校验返回值
                String msg;
                String key = "发票主信息";

                // 金额模式
                msg = checkStringParam(invoiceDetails.getJems(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_JEMS);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 蓝字发票标志
                msg = checkStringParam(invoiceDetails.getLzfpbz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_LZFPBZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 发票票种
                msg = checkStringParam(invoiceDetails.getFppz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_FPPZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 单号类型
                msg = checkStringParam(invoiceDetails.getDhlx(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_DHLX);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 单号
                msg = checkStringParam(invoiceDetails.getDh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_DH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 特定要素
                msg = checkStringParam(invoiceDetails.getTdys(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_TDYS);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 差额征税类型代码
                msg = checkStringParam(invoiceDetails.getCezslxdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_CEZSLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方名称
                msg = checkStringParam(invoiceDetails.getGmfmc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_GMFMC);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方纳税人识别号
                msg = checkStringParam(invoiceDetails.getGmfnsrsbh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_GMFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方名称
                msg = checkStringParam(invoiceDetails.getXsfmc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_XSFMC);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方纳税人识别号
                msg = checkStringParam(invoiceDetails.getXsfnsrsbh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_XSFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 合计金额
                msg = checkBigDecimalParam(invoiceDetails.getHjje(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_HJJE);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 合计税额
                msg = checkBigDecimalParam(invoiceDetails.getHjse(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_HJSE);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 价税合计
                msg = checkBigDecimalParam(invoiceDetails.getJshj(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_JSHJ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 开票人
                msg = checkStringParam(invoiceDetails.getKpr(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_KPR);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 对应蓝字发票号码
                msg = checkStringParam(invoiceDetails.getDylzfphm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_DYLZFPHM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 红字确认信息单编号
                msg = checkStringParam(invoiceDetails.getHzqrxxdbh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_HZQRXXDBH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 红字确认单uuid
                msg = checkStringParam(invoiceDetails.getHzqrduuid(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_HZQRDUUID);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 备注
                msg = checkStringParam(invoiceDetails.getBz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_BZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 交易机构id
                msg = checkStringParam(invoiceDetails.getQydjid(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_QYDJID);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 作废红冲原因
                msg = checkStringParam(invoiceDetails.getZfchyy(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_ZFCHYY);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 数据来源
                msg = checkStringParam(invoiceDetails.getSjly(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_SJLY);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 匹配状态
                msg = checkStringParam(invoiceDetails.getPpzt(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_PPZT);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 是否不动产
                msg = checkStringParam(invoiceDetails.getSfbdc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_SFBDC);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 征税方式
                msg = checkStringParam(invoiceDetails.getZsfs(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_ZSFS);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 创建人
                msg = checkStringParam(invoiceDetails.getCreatBy(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEDETAILS_CREATBY);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
            } else {
                ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票主信息", "发票数据为空");
                errorVerifyList.add(errorVerify);
            }

            // 校验发票明细信息
            if (CollectionUtil.isNotEmpty(invoiceItemsList)) {
                for (int j = 0; j < invoiceItemsList.size(); j++) {
                    // 参数校验返回值
                    String msg;
                    String key = "第" + (j + 1) + "行发票明细信息";
                    VmsFullOutInvoiceItems invoiceItems = invoiceItemsList.get(j);

                    // 明细序号
                    msg = checkLongParam(invoiceItems.getMxxh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_MXXH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 对应蓝字发票明细序号
                    msg = checkLongParam(invoiceItems.getDylzfpmxxh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_DYLZFPMXXH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 项目名称
                    msg = checkStringParam(invoiceItems.getXmmc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_XMMC);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 规格型号
                    msg = checkStringParam(invoiceItems.getGgxh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_GGXH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 单位
                    msg = checkStringParam(invoiceItems.getDw(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_DW);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 数量
                    msg = checkStringParam(invoiceItems.getSl(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_SL);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 单价
                    msg = checkStringParam(invoiceItems.getDj(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_DJ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 金额
                    msg = checkBigDecimalParam(invoiceItems.getJe(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_JE);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 税率/征收率
                    msg = checkBigDecimalParam(invoiceItems.getSlv(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_SLV);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 税额
                    msg = checkBigDecimalParam(invoiceItems.getSe(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_SE);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 扣除额
                    msg = checkBigDecimalParam(invoiceItems.getKce(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_KCE);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 商品和服务税收分类合并编码
                    msg = checkStringParam(invoiceItems.getSphfwssflhbbm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_SPHFWSSFLHBBM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 发票行性质
                    msg = checkStringParam(invoiceItems.getFphxz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_FPHXZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 产品编码
                    msg = checkStringParam(invoiceItems.getCpbm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_CPBM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 计税方法
                    msg = checkStringParam(invoiceItems.getJsff(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_JSFF);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 征税项目
                    msg = checkStringParam(invoiceItems.getZsxm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_ZSXM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 优惠政策标识
                    msg = checkStringParam(invoiceItems.getYhzcbs(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_YHZCBS);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 创建人
                    msg = checkStringParam(invoiceItems.getCreatBy(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_CREATBY);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                }
            } else {
                ErrorVerifyVo errorVerify = buildErrorVerify(num, "发票明细信息", "发票明细数据为空");
                errorVerifyList.add(errorVerify);
            }

            // 校验发票非必填扩展信息
            if (ObjectUtil.isNotEmpty(invoiceItemsExp)) {
                // 参数校验返回值
                String msg;
                String key = "发票非必填扩展信息";

                // 增值税即征即退代码
                msg = checkStringParam(invoiceItemsExp.getZzsjzjtdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_ZZSJZJTDM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 收购发票类型代码
                msg = checkStringParam(invoiceItemsExp.getSgfplxdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_SGFPLXDM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 出口业务适用政策代码
                msg = checkStringParam(invoiceItemsExp.getCkywsyzcdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_CKYWSYZCDM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方地址
                msg = checkStringParam(invoiceItemsExp.getGmfdz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFDZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方电话
                msg = checkStringParam(invoiceItemsExp.getGmfdh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFDH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方开户行
                msg = checkStringParam(invoiceItemsExp.getGmfkhh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFKHH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方账号
                msg = checkStringParam(invoiceItemsExp.getGmfzh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFZH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方经办人姓名
                msg = checkStringParam(invoiceItemsExp.getGmfjbr(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFJBR);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方经办人证件号码
                msg = checkStringParam(invoiceItemsExp.getJbrsfzjhm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_JBRSFZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方经办人联系电话
                msg = checkStringParam(invoiceItemsExp.getGmfjbrlxdh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFJBRLXDH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 购买方自然人标志
                msg = checkStringParam(invoiceItemsExp.getGmfzrrbz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_GMFZRRBZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方地址
                msg = checkStringParam(invoiceItemsExp.getXsfdz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_XSFDZ);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方电话
                msg = checkStringParam(invoiceItemsExp.getXsfdh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_XSFDH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方开户行
                msg = checkStringParam(invoiceItemsExp.getXsfkhh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_XSFKHH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 销售方账号
                msg = checkStringParam(invoiceItemsExp.getXsfzh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_XSFZH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 收款银行名称
                msg = checkStringParam(invoiceItemsExp.getSkyhmc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_SKYHMC);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 收款银行账号
                msg = checkStringParam(invoiceItemsExp.getSkyhzh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_SKYHZH);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 结算方式
                msg = checkStringParam(invoiceItemsExp.getJsfs(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_JSFS);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 开票人证件号码
                msg = checkStringParam(invoiceItemsExp.getKprzjhm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_KPRZJHM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 开票人证件类型
                msg = checkStringParam(invoiceItemsExp.getKprzjlx(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_KPRZJLX);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 收款人
                msg = checkStringParam(invoiceItemsExp.getSkrxm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_SKRXM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 复核人
                msg = checkStringParam(invoiceItemsExp.getFhrxm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_FHRXM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 区域代码
                msg = checkStringParam(invoiceItemsExp.getQydm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_QYDM);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
                // 应税行为发生地
                msg = checkStringParam(invoiceItemsExp.getYsxwfsd(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_EXP_YSXWFSD);
                if (StringUtils.isNotBlank(msg)) {
                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                    errorVerifyList.add(errorVerify);
                }
            }

            // 校验发票附加要素信息
            if (CollectionUtil.isNotEmpty(invoiceItemsAddList)) {
                for (int j = 0; j < invoiceItemsAddList.size(); j++) {
                    // 参数校验返回值
                    String msg;
                    String key = "第" + (j + 1) + "行发票附加要素信息";
                    VmsFullOutInvoiceItemsAdd invoiceItemsAdd = invoiceItemsAddList.get(j);

                    // 附加要素名称
                    msg = checkStringParam(invoiceItemsAdd.getFjysmc(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_ADD_FJYSMC);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 附加要素类型
                    msg = checkStringParam(invoiceItemsAdd.getFjyslx(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_ADD_FJYSLX);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                    // 附加要素值
                    msg = checkStringParam(invoiceItemsAdd.getFjysz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICEITEMS_ADD_FJYSZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                }
            }

            // 校验发票特定业务信息
            if (CollectionUtil.isNotEmpty(invoiceTdywList)) {
                for (int j = 0; j < invoiceTdywList.size(); j++) {
                    // 参数校验返回值
                    String msg;
                    String key = "第" + (j + 1) + "行发票特定业务信息";
                    VmsFullOutInvoiceTdyw invoiceTdyw = invoiceTdywList.get(j);

                    // 不动产坐落地址（省）
                    msg = checkStringParam(invoiceTdyw.getBdczldzS(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_BDCZLDZS);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 不动产坐落地址（市）
                    msg = checkStringParam(invoiceTdyw.getBdczldzS1(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_BDCZLDZS1);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 不动产坐落地址（详细地址）
                    msg = checkStringParam(invoiceTdyw.getBdczldzXxdz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_BDCZLDZXXDZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 租赁期起止
                    msg = checkStringParam(invoiceTdyw.getZlqqz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_ZLQQZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 跨地（市）标志
                    msg = checkStringParam(invoiceTdyw.getKdsbz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_KDSBZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 产权证书/不动产权证号
                    msg = checkStringParam(invoiceTdyw.getCqzsbh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CQZSBH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 不动产单位代码
                    msg = checkStringParam(invoiceTdyw.getBdcdwdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_BDCDWDM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 网签合同备案编号
                    msg = checkStringParam(invoiceTdyw.getWqhtbabh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_WQHTBABH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 土地增值税项目编号
                    msg = checkStringParam(invoiceTdyw.getTdzzsxmbh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_TDZZSXMBH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 核定计税价格
                    msg = checkBigDecimalParam(invoiceTdyw.getHdjsjg(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_HDJSJG);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 实际成交含税金额
                    msg = checkBigDecimalParam(invoiceTdyw.getSjcjhsje(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_SJCJHSJE);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 面积单位
                    msg = checkStringParam(invoiceTdyw.getMjdw(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_MJDW);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 多方共同购买标志
                    msg = checkStringParam(invoiceTdyw.getDfgtgmbz(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_DFGTGMBZ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    if (CommonConstant.STR_Y.equals(invoiceTdyw.getDfgtgmbz())) {
                        if (CollectionUtil.isNotEmpty(invoiceTdyw.getTdywItemList())) {
                            for (int k = 0; k < invoiceTdyw.getTdywItemList().size(); k++) {
                                VmsFullOutInvoiceTdywItem invoiceTdywItem = invoiceTdyw.getTdywItemList().get(k);
                                // 共同购买方
                                msg = checkStringParam(invoiceTdywItem.getGtgmf(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_GTGMF);
                                if (StringUtils.isNotBlank(msg)) {
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                                    errorVerifyList.add(errorVerify);
                                }

                                // 证件类型
                                msg = checkStringParam(invoiceTdywItem.getZjlx(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_ZJLX);
                                if (StringUtils.isNotBlank(msg)) {
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                                    errorVerifyList.add(errorVerify);
                                }

                                // 证件号码
                                msg = checkStringParam(invoiceTdywItem.getZjhm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_ZJHM);
                                if (StringUtils.isNotBlank(msg)) {
                                    ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                                    errorVerifyList.add(errorVerify);
                                }
                            }
                        }
                    }

                    // 出行人序号
                    msg = checkIntegerParam(invoiceTdyw.getCxrxh(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CXRXH);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 出行人
                    msg = checkStringParam(invoiceTdyw.getCxr(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CXR);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 出行人证件类型
                    msg = checkStringParam(invoiceTdyw.getCxrzjlxdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CXRZJLXDM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 有效身份证件号
                    msg = checkStringParam(invoiceTdyw.getSfzjhm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_SFZJHM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 出行日期
                    msg = checkStringParam(invoiceTdyw.getChuxrq(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CHUXRQ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 旅客出发地
                    msg = checkStringParam(invoiceTdyw.getCfd(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_CFD);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 旅客到达地
                    msg = checkStringParam(invoiceTdyw.getDdd(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_DDD);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 交通工具类型
                    msg = checkStringParam(invoiceTdyw.getJtgjlxdm(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_JTGJLXDM);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }

                    // 座位等级
                    msg = checkStringParam(invoiceTdyw.getZwdj(), CheckParamEnum.CHECK_VMS_FULL_OUTINVOICE_TDYW_ZWDJ);
                    if (StringUtils.isNotBlank(msg)) {
                        ErrorVerifyVo errorVerify = buildErrorVerify(num, key, msg);
                        errorVerifyList.add(errorVerify);
                    }
                }
            }
        }

        return errorVerifyList;
    }

    /**
     * 构建返回错误实体
     */
    private ErrorVerifyVo buildErrorVerify(String num, String key, String value) {
        ErrorVerifyVo errorVerify = new ErrorVerifyVo();
        errorVerify.setNum(num);
        errorVerify.setKey(key);
        errorVerify.setValue(value);
        return errorVerify;
    }

    /**
     * 校验String类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkStringParam(String param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (StringUtils.isBlank(param)) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验是否为固定格式
        if (checkParamEnum.getFixedFormal()) {
            String[] split = param.split("：");
            if (split.length != 2) {
                errorMsg.add(checkParamEnum.getParamName() + "格式不正确，请选择单元格下拉框列表数据");
            }
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

    /**
     * 校验BigDecimal类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkBigDecimalParam(BigDecimal param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据整数位和小数位最大长度
        if (StringUtils.isNotBlank(checkParamEnum.getNumberFormat())) {
            String[] split = checkParamEnum.getNumberFormat().split(",");
            if (split.length == 2) {
                // 获取整数位和小数位最大长度
                int maxIntegerDigits = Integer.parseInt(split[0]);
                int maxDecimalDigits = Integer.parseInt(split[1]);
                // 去掉尾部多余的0
                BigDecimal bigDecimal = param.stripTrailingZeros();
                // 获取参数的整数位数和小数位数
                int integerDigits = bigDecimal.precision() - bigDecimal.scale();
                int decimalDigits = Math.max(bigDecimal.scale(), 0);

                // 判断是否满足最大长度限制
                if (integerDigits > maxIntegerDigits || decimalDigits > maxDecimalDigits) {
                    errorMsg.add(checkParamEnum.getParamName() + "数据不合法,整数位最大长度为" + maxIntegerDigits + ",小数位最大长度为" + maxDecimalDigits);
                }
            }
        }

        return String.join("，", errorMsg);
    }

    /**
     * 校验Long类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkLongParam(Long param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.toString().length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

    /**
     * 校验Integer类型参数
     *
     * @param param          待校验的参数
     * @param checkParamEnum 数据校验枚举类
     * @return 如校验不通过返回错误信息
     */
    private String checkIntegerParam(Integer param, CheckParamEnum checkParamEnum) {
        List<String> errorMsg = new ArrayList<>();

        // 如果字段为空，校验是否必填
        if (null == param) {
            if (checkParamEnum.getRequired()) {
                errorMsg.add(checkParamEnum.getParamName() + "为必填信息项");
                return String.join("，", errorMsg);
            }
            return String.join("，", errorMsg);
        }

        // 校验数据最大长度
        if (checkParamEnum.getMaxLength() != 0) {
            if (param.toString().length() > checkParamEnum.getMaxLength()) {
                errorMsg.add(checkParamEnum.getParamName() + "数据不合法,最大长度为" + checkParamEnum.getMaxLength());
            }
        }

        return String.join("，", errorMsg);
    }

}
